

		UnixLib v3.6c Maintenance Documentation


Directories marked '#' below contain proprietary source code. Source code
in these directories is Copyright 1990/1991/1992/1993 H.Rogers and XFM
Software, and may only be distributed or modified in connection with UnixLib
development. All other use or distribution is strictly prohibited.
This entire paragraph and the list of directories below must be present
in a file called "ReadMe" in a prominent place on all media used to
distribute the aforementioned source code or derivations thereof. Failure
to comply with the above requirements is breach of copyright and other
international laws.


	!Alias		      * Alias file (see "ReadMe")
	!Boot			!Boot for UnixLib maintenance
	clib		      * Library directory
	clib.h		      * UnixLib ANSI header files
	clib.o		      * UnixLib directory
	clib.o.unixlib	      * UnixLib itself
	clib.sys.h	      * UnixLib specific header files
	etc		      * UnixLib version of /etc
	ReadMe		      * Documentation for UnixLib - this file
	src			Source code
	src.ReadMe		Documentation for source code
	src.o			UnixLib portable object code
	src.c		      # UnixLib portable source code
	src.stdio.o		UnixLib stdio object code
	src.stdio.c	      # UnixLib stdio source code
	src.unix.c		UnixLib UNIX emulation source code
	src.unix.o		UnixLib UNIX emulation object code
	src.sys.c		UnixLib RiscOS related source code
	src.sys.s		UnixLib RiscOS related source code (ARM code)
	src.sys.o		UnixLib RiscOS related object code
	test			UnixLib test programs
	test.ReadMe		Documentation for test programs


Asterisked files/directories are those that are necessary to compile
programs with UnixLib. If you are installing UnixLib onto a hard disk you
are advised not to change the organization of the directory tree other than
to move etc into the root directory, since updates will be issued with
this structure.

		How UnixLib Works

First - a comment on how the functions/variable definitions are
split up between various object files. Storage allocation has been
carefully thought out so as to minimise loading of unnecessary
object files. This is why work variables used only in a particular
object file, but which have to be initialised, will not be defined
in the same place as where they are used. Thus: beware of shifting code
or variables from one file to another. The minimum executable size is
currently 24k.

In particular the stdio and vfork initialization/exit routines are
conditionally linked in using AOF 'weak links' - if a program doesn't
use stdio it won't get linked in with it. Similarly vfork(). The weak
links are in sys.s._syslib and are documented in <sys/syslib.h>.

It is a good idea to look at the header files <sys/syslib.h> and
<sys/unix.h> when reading this document - they are (hopefully :-))
well commented. Also <sys/dev.h> and <sys/tty.h> should be understood.

The entry point for all programs is in sys.s._syslib. This is __main().
__main() sets up the stack (__stack), break (cf UNIX) (__break), pointer
to the command line used to invoke the program (__cli), and program
start time (__time). The stack grows down from the top of user memory
(as read by OS_GetEnv), and the break grows upwards from the top of the
program data (RW) area.
	__main() then calls _main() which is a C function (in sys.c.syslib).
_main() initialises the signal handlers, exception handlers, floating point
status (__fpflag), memory allocation (malloc() etc.), unix (calling
__unixinit()), and stdio (calling __stdioinit()), in that order. Lastly
_main() calls main() with the argc,argv that were generated by __unixinit().
	__unixinit() first checks for the presence of the environment variable
UnixLib$env. If this is set, it contains a value which is the address of a
proc structure that should be inherited by the process, and no further
initialisation is necessary (see <sys/unix.h> for details of the proc
structure) - this is the case when one UnixLib program calls another using
vfork() and execve(). The proc structure is pointed to by __u and is
documented in <sys/unix.h> - look at this.
	If UnixLib$env is unset, a default proc structure and FD set are
generated, and FDs 0,1 and 2 are connected to the terminal defined by
Unix$tty. The invoking command line (__cli) is copied in SVC mode, then
scanned to form the argc, argv array and set any command line redirection.
Lastly the environment variable Unix$uid is checked & processed as described
in "ReadMe". __unixinit() also initialises the __fsdir[] structure array and
__pipedir according to UnixFS$xxx and Unix$pipe as described in "ReadMe".

Various function calls are generated inline by the C compiler, and these
functions are all in sys.s._syslib. They include the division, modulus,
pointer check, stack overflow & profiling functions. The __memcpy() and
__memset() functions are now in sys.s._mem: These are also called by the
library memcpy() and memset() functions (and are written with some care in
order to be particularly fast - approx. 4 times faster than in v3.2).
Note the profiling functions merely return - profiling remains effectively
unimplemented.

The low level exception handlers are in sys.s._signal, and the higher
level UNIX abstraction (signal handlers) are dealt with in sys.c.signal.
Note the use of OS_CallBack. It is unwise to mess with the ARM code in
s._signal and s._syslib unless you *really* understand what's going on -
the exception handling in particular is (and has to be) extremely nasty.
Note UnixLib can recover from *all* signals/exceptions, unlike Acorn's
AnsiLib, and implements far more (see <signal.h> and <sys/syslib.h>). 

UNIX system calls are implemented in unix.c.*, with the exception of alarm(),
brk(), exit(), sbrk(), execve(), raise(), signal(), & vfork() since these
interact closely with both RiscOS and the UnixLib internals - they are in
sys.c.*.

sys.c.errlist contains the UNIX error list; RiscOS errors are flagged by
calling __seterr() - in sys.c.os. This sets errno to EOS and sets the error
string for perror() etc. You can also set the error string returned by
perror() by calling __seterr_().

Also in the sys.s directory are the FP math routines, setjmp() & longjmp(),
the ARM code parts of execve() and vfork(), and the RiscOS interface os_*().
setjmp() & longjmp() modify their behaviour according to whether the FP is
present or not - if not they don't bother saving the FP status and thus avoid
generating SIGILL. execve() and vfork() are documented below.
	The RiscOS interface is documented in <sys/os.h> and is pretty
comprehensive. You can pass a null pointer to OS functions that store result
registers in integer arrays, in which case no results are stored. os_swi(n,0)
calls SWI n and assumes it doesn't require arguments (if it does it'll use
garbage). os_print() & os_prhex() are useful for debugging messages as they
guarantee output - note you must use OS newlines with os_print() i.e. "\r\n"
not just "\n" as unix expects.

vfork() is implemented as an alias to setjmp() and longjmp() with some
manipulation of the UNIX environment... Read the source code (sys.c.vfork
and sys.s._vfork) to understand what it does/how it works. Also read the UNIX
man page for vfork() - it's semantics are *not* normal. Despite it's
restrictions vfork() can be used interchangeably with fork() as long as some
care is taken...

execve() checks whether the current process is a child from a previous call
to vfork() - if it isn't then it calls __reset() (see <sys/syslib.h>) and
then overlays the current program with the new one (as per UNIX). If on the
other hand it's a child, then it:

	0) Overwrites argv,argc and sets up a cli from the argc,argv array to
subsequently pass to OS_CLI.
	1) Closes all O_EXECCL file descriptors & turns off any alarm().
	2) Turns off the __U_PPROC flag (see <sys/unix.h>) so that the
subprogram is forced to exit fully.
	3) Resets all exception handlers.
	4) Calculates __exshift - the gap between the break and bottom of the
stack - this is the amount by which the program will be copied up freeing
memory for the subprogram.
	5) Modifies the proc structure using the ushift() macro so that when
it is copied up, all pointers are offset and thus correct. Note the check
to see if each pointer is in the text/data area (the data could be on the
stack and thus remain unmoved). This is done so that the proc structure can
be inherited by the subprogram using UnixLib$env (see above).
	6) Sets up __exec() & UnixLib$env.
	7) Calls __exec() with the cli set up in 0).

	8) __exec() (in sys.s._exec) actually performs the copy up operation,
sets the OS_GetEnv HIMEM to below the moved text area, sets up an exit
handler, and calls OS_CLI. The exit handler resets the HIMEM, performs the
copy down operation, and eventually calls __exret().

	9) __exret() shifts the proc structure pointers back down using the
dshift() macro.
	10) reinstalls exception handlers.
	11) kills UnixLib$env in case it's still set.
	12) Turns on the __U_PPROC flag.
	13) Calls __vret() with the subprogram's Sys$ReturnCode.
	14) __vret() returns as if from a vfork() back to the parent.

UnixLib I/O is abstracted by the __dev[] array defined in <sys/dev.h> and
in unix.c.dev. The source code for open(), etc. is pretty self explanatory.
unix.c.dev contains the FileCore interface, unix.c.tty the tty interface.
Pipes are also in unix.c.dev. Note that the pipe() system call itself is in
unix.c.pipe. Look at <sys/unix.h> to understand the __u->u_file[] array of
file descriptors.

UNIX -> RiscOS filename conversion is in unix.c.uname.

Apologies if my indentation/coding style doesn't match with yours!
In any case please maintain the library in a consistent format. Also
apologies for the terse style of this documentation - You're probably
better off reading the source code anyway...


		How to Submit Patches/Bug Reports

If you find a bug, or patch a piece of code, please Email me with either
the source code you patched (with a description of what's changed), or a
description of the bug with any sample code that can be used to recreate
the circumstances. See "ReadMe" for how to contact me.
